package cm.tl.pms.common.config;

import cm.tl.pms.common.constant.BizConstants;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.*;

@Aspect
@Configuration
@Slf4j
public class ControllerLogAspect {

    static List<String> PRINT_HEADER_LIST = Arrays.asList("authorization", "x-real-ip", "remote-host",
            "x-forwarded" + "-proto", "host", "connection", "x-forwarded-for", "accept-encoding", "user-agent");

    // 定义切点Pointcut
    @Pointcut("execution(* com.bc.*.controller..*.*(..))")
    public void controllers() {
    }

    @Around("controllers()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        StringBuilder sb = new StringBuilder();
        String uri = parseRequestInfo(pjp, sb);
        // result的值就是被拦截方法的返回值
        Long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        Long useTimeMillis = System.currentTimeMillis() - start;
        String resultStr = JSON.toJSONString(result);
        // if (resultStr != null && resultStr.length() > 500 && !completePrint()) {
        // resultStr = resultStr.substring(0, 500) + "...(省略更多结果打印)";
        // }
        // sb.append("result:");
        if (BizConstants.IGNORE_RESULT_LIST.contains(uri)) {
            sb.append("返回内容长度:" + resultStr.length());
        } else {
            sb.append(resultStr);
        }
        // sb.append("|||TOTAL-TIME:" + useTimeMillis);
        sb.append("|||" + useTimeMillis);
        if (!BizConstants.IGNORE_URI_LIST.contains(uri)) {
            log.info(sb.toString());
        }

        return result;
    }

    @AfterThrowing(value = "controllers()", throwing = "exception")
    public void exceptionLog(JoinPoint pjp, Exception exception) {
        StringBuilder sb = new StringBuilder();
        parseRequestInfo(pjp, sb);
        sb.append("exception:");
        sb.append(exception.getMessage());
        log.error(sb.toString());
    }


    private String parseRequestInfo(JoinPoint pjp, StringBuilder sb) {
        HttpServletRequest request = getRequestFromThreadLocal();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String header = getHeaderJsonStr(request);
        String queryString = request.getQueryString();
        Object[] args = pjp.getArgs();
        String params = "";
        //获取请求参数集合并进行遍历拼接
        if (args.length > 0) {
            Object object = args[0];
            if (object != null) {
                Map map = getKeyAndValue(object);
                params = JSON.toJSONString(map);
            }
        }

        if (StringUtils.isBlank(params)) {
            params = StringUtils.isEmpty(queryString) ? "{}" : queryString;
        }
        sb.append(method);
        sb.append("|||");
        sb.append(uri);
        sb.append("|||");
        sb.append(header);
        sb.append("|||");
        if (BizConstants.IGNORE_PARAM_LIST.contains(uri)) {
            sb.append("参数长度:" + params.length());
        } else {
            sb.append(params);
        }
        sb.append("|||");
        return uri;
    }


    private HttpServletRequest getRequestFromThreadLocal() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        return sra.getRequest();
    }

    private String getHeaderJsonStr(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String, String> map = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            if (PRINT_HEADER_LIST.contains(name.toLowerCase())) {
                String value = request.getHeader(name);
                map.put(name, value);
            }
        }
        return JSON.toJSONString(map);
    }

    public static Map<String, Object> getKeyAndValue(Object obj) {
        Map<String, Object> map = new HashMap<>();
        // 得到类对象
        Class userCla = obj.getClass();
        /* 得到类中的所有属性集合 */
        Field[] fs = userCla.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            f.setAccessible(true);
            try {
                Object val = f.get(obj);
                if (val instanceof HttpServletResponse || val instanceof HttpServletRequest) {
                    // 不能搞这两货
                } else {
                    map.put(f.getName(), val);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
